package SIC.Controleur.Reasoner;

import java.io.File;
import java.util.Iterator;
import java.util.Set;

import org.semanticweb.owlapi.apibinding.OWLManager;
import org.semanticweb.owlapi.model.IRI;
import org.semanticweb.owlapi.model.OWLClass;
import org.semanticweb.owlapi.model.OWLOntology;
import org.semanticweb.owlapi.model.OWLOntologyCreationException;
import org.semanticweb.owlapi.model.OWLOntologyManager;
import org.semanticweb.owlapi.reasoner.Node;
import org.semanticweb.owlapi.reasoner.OWLReasoner;
import org.semanticweb.owlapi.util.DefaultPrefixManager;

import com.clarkparsia.pellet.owlapiv3.PelletReasonerFactory;

/**
 * Cette classe permet de lancer le Raissonneur PELLET sur le fichier de correspondance OWL
 * @see http://owlapi.svn.sourceforge.net/viewvc/owlapi/v3/trunk/examples/src/main/java/org/coode/owlapi/examples/Example8.java?view=markup
 */
public class Reasoner {
	
	//--------------------------------------------
	//					ATTRIBUTS
	//--------------------------------------------

	/**  Le préfixe à utiliser */
	private DefaultPrefixManager pm;
	
	/** Le raisonneur */
	private OWLReasoner reasoner;
	
	/** La racine de la hiérarchie de classe inférée */
	private Node<OWLClass> topNode;
	
	/** La liste des classes insatisfiables */
	private String insatisfiable = "";
	
	/** La hiérarchie de classe inférée (depuis la racine) */
	private String hierarchieDeClassesInferee = "";

	//--------------------------------------------
	//				CONSTRUCTEUR
	//--------------------------------------------
	
	public Reasoner() {}
	
	//--------------------------------------------
	//				TRAITEMENT
	//--------------------------------------------
	
	/**
	 * Lance le raisonneur
	 * @param fichierOWLCAOFAO emplacement du fichier OWL de mapping
	 * @param fichierOWLCAO emplacement du fichier OWL pour le CAO
	 * @param fichierOWLFAO emplacement du fichier OWL pour le FAO
	 */
    public void lancerRaisonneur(String fichierOWLCAOFAO, String fichierOWLCAO, String fichierOWLFAO) {

    	insatisfiable = "";
    	hierarchieDeClassesInferee = "";
    	
        try {

            OWLOntologyManager manager = OWLManager.createOWLOntologyManager();

            //on charge les ontologies qui seront utiles
            manager.loadOntologyFromOntologyDocument(IRI.create((new File(fichierOWLCAO)).toURI()));
            manager.loadOntologyFromOntologyDocument(IRI.create((new File(fichierOWLFAO)).toURI()));
            
            OWLOntology ontologie = manager.loadOntologyFromOntologyDocument(IRI.create((new File(fichierOWLCAOFAO)).toURI()));

            pm = new DefaultPrefixManager(""+ontologie.getOntologyID());
            
            PelletReasonerFactory pelletFactory = PelletReasonerFactory.getInstance();
            
            reasoner = pelletFactory.createReasoner(ontologie);
            
            //on lance le raisonneur
            reasoner.precomputeInferences();
   
            Node<OWLClass> bottomNode = reasoner.getUnsatisfiableClasses();
            Set<OWLClass> unsatisfiable = bottomNode.getEntitiesMinusBottom();
            
            insatisfiable += "Liste des classes insatisfiables : \n";
            
            if (!unsatisfiable.isEmpty())
            {
            	insatisfiable += "Les classes suivantes sont insatisfiables : \n";
                
                for(OWLClass cls : unsatisfiable)
                	insatisfiable += "    " + cls;
            }
            else insatisfiable += "Il n'y a pas de classe insatisfiable.";  
            
            insatisfiable +="\n";

            topNode = reasoner.getTopClassNode();

        }
        catch(UnsupportedOperationException exception) {
            System.out.println("Opération non supportée par le raisonneur.");
        }
        catch (OWLOntologyCreationException e) {
            System.out.println(e.getMessage());
        }
    }

	//--------------------------------------------
	//					AFFICHAGE
	//--------------------------------------------
    
    @Override
    public String toString()
    {
    	toStringArbre(topNode,0);
    	return "On raisonne sur l'ontologie  : "
    			+ pm.getDefaultPrefix() + "\n\n"
    			+ insatisfiable
    			+ "\nHiérarchie de classes inférée :\n"
    			+ hierarchieDeClassesInferee + "\n";
    }

    /**
     * Sauvegarde la hiérarchie de classes inférée (récursif)
     * @param parent noeud parent
     * @param depth profondeur souhaitée
     */
    private void toStringArbre(Node<OWLClass> parent, int depth) {
    	
        // We don't want to print out the bottom node (containing owl:Nothing and unsatisfiable classes)
        // because this would appear as a leaf node everywhere
    	
        if(parent.isBottomNode()) {
            return;
        }
        
        // Print an indent to denote parent-child relationships
        printIndent(depth);
        
        // Now print the node (containing the child classes)
        printNode(parent);
        
        for(Node<OWLClass> child : reasoner.getSubClasses(parent.getRepresentativeElement(), true)) {
            // Recurse to do the children.  Note that we don't have to worry about cycles as there
            // are non in the inferred class hierarchy graph - a cycle gets collapsed into a single
            // node since each class in the cycle is equivalent.
            toStringArbre(child, depth + 1);
        }
        
    }

    /** L'indentation */
    private void printIndent(int depth) {
        for(int i = 0; i < depth; i++) {
        	hierarchieDeClassesInferee += "    ";
        }
    }

    /**
     * Sauvegarde le contenu du noeud
     * @param node un noeud
     */
    private void printNode(Node<OWLClass> node) {
        // Print out a node as a list of class names in curly brackets
    	hierarchieDeClassesInferee += "{";
        for(Iterator<OWLClass> it = node.getEntities().iterator(); it.hasNext(); ) {
            OWLClass cls = it.next();
            // User a prefix manager to provide a slightly nicer shorter name
            hierarchieDeClassesInferee += pm.getShortForm(cls) + "";
            if (it.hasNext()) {
            	hierarchieDeClassesInferee += "  ";
            }
        }
        hierarchieDeClassesInferee += "}\n";
    }
	
}
